#include "creature.hpp"

Creature* player = new Creature(Names::CREATURE_PLAYER);

void CreatureProperties::Set(int hp, int mp, int att, int def, int hungry, int speed, int strength, int dex, int intelli, int power, float burden){
    hp_ = hp;
    mp_ = mp;
    strength_ = strength;
    attack_ = att;
    defence_ = def;
    hungry_ = hungry;
    speed_ = speed;
    dex_ = dex;
    burden_ = burden;
    power_ = power;
    intelli_ = intelli;
}

Creature::Creature(Names name):Object(ObjType::CREATURE){
    SetName(name);
}

void Creature::Attack(Object* target){
    if(target){
        if(target->GetType()==ObjType::CREATURE){
            Creature* other = dynamic_cast<Creature*>(target);
            DmgState state;
            int dmg = CalcDamage(properties_, other->properties_, state);
            applyAttack(other, dmg, state);
        }else if(target->GetType()==ObjType::WALL){
            diary.AddText(string(GetName())+"锤了一下墙，看上去并没有什么作用");
        }else{
            diary.AddText("什么也没有发生");
        }
    }else{
        diary.AddText(string(GetName())+"打了一下空气");
    }
}

void Creature::Attack(int relate_x, int relate_y){
    Object* obj = worldmodel.GetLayer()->GetObjAt(_position.x+relate_x, _position.y+relate_y);
    Attack(obj);
}

void Creature::MoveWithColliTest(int relate_x, int relate_y){
    LayerModel* layer = worldmodel.GetLayer();
    SDL_Point pos = {GetPosition().x+relate_x, GetPosition().y+relate_y};
    Object* creature = layer->GetCreatureAt(pos.x, pos.y);
    if(creature){   // 如果存在生物，将移动指令转化为攻击指令
        Attack(dynamic_cast<Creature*>(creature));
    }else{
        Object* obj = layer->GetObjAt(pos.x, pos.y);
        if(obj->GetType()==ObjType::WALL){  // 如果是墙，给予墙的碰撞检测
            Move(relate_x, relate_y);
            if(obj->IsCollidable())
                Collide(this, dynamic_cast<CollidableObj*>(obj));
        }else if(obj->GetType()==ObjType::GROUND){  // 如果是地面，则移动之后查看一下地面上的物体，并将物体输出到diary
            cout<<*obj<<endl;
            if(!dynamic_cast<Ground*>(obj)->Empty())
                Look(pos.x, pos.y);
            Move(relate_x, relate_y);
        }
    }
}

void Creature::Look(int x, int y){
    Object* obj = worldmodel.GetLayer()->GetCreatureAt(x, y);
    if(obj && obj!=this){    // 首先看地上有没有除了自己以外的生物，如果有生物，则直接显示生物信息
        char buffer[1024] = {0};
        sprintf(buffer, "there is a %s", obj->GetName().c_str());
        diary.AddText(buffer, {200, 50, 50});
    }else{
        Object* obj = worldmodel.GetLayer()->GetObjAt(x, y);
        if(obj->GetType()==ObjType::WALL){  // 如果是墙则直接输出
            diary.AddText("there is a wall");
        }else if(obj->GetType()==ObjType::GROUND){ // 如果地面则输出地面上的东西
            ObjectList list = dynamic_cast<Ground*>(obj)->GetObjects();
            if(list.empty()){
                diary.AddText("这里只是普通地板");
            }else{
                string names;
                for(Object* obj : list)
                    names += obj->GetName() +",";
                diary.AddText("这儿有 " + names, {50, 200, 50});
            }
        }
    }
}

void Creature::applyAttack(Creature* other, int dmg, DmgState state){
    other->properties_.hp_ -= dmg;
    char buffer[1024] = {0};
    if(state==DmgState::NORMAL){
        sprintf(buffer, "%s 攻击了 %s，造成 %d 点伤害", GetName().c_str(), other->GetName().c_str(), dmg);
    }else if(state==DmgState::CRITICAL_ATTACK){
        sprintf(buffer, "%s 暴击了 %s，造成 %d 点伤害", GetName().c_str(), other->GetName().c_str(), dmg);
    }else if(state==DmgState::CRITICAL_FAULT){
        sprintf(buffer, "%s 出现了重大失误，没有击中 %s", GetName().c_str(), other->GetName().c_str());
    }
    diary.AddText(buffer);
}
